package cn.felord.security.autoconfigure.authentication.miniapp.wechat;


import cn.felord.security.autoconfigure.authentication.miniapp.MiniAppSessionService;
import cn.felord.security.autoconfigure.authentication.miniapp.MiniAppUserDetailsService;
import cn.felord.security.autoconfigure.LoginAntPathPatterns;
import cn.felord.security.autoconfigure.TokenGenerator;
import cn.felord.security.autoconfigure.authentication.AbstractLoginFilterConfigurer;
import cn.felord.security.autoconfigure.authentication.LoginFilterSecurityConfigurer;
import cn.felord.security.autoconfigure.handler.LoginAuthenticationSuccessHandler;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;


public class WechatMiniAppLoginFilterConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractLoginFilterConfigurer<H, WechatMiniAppLoginFilterConfigurer<H>, WechatMiniAppAuthenticationFilter, LoginFilterSecurityConfigurer<H>> {
    private MiniAppUserDetailsService miniAppUserDetailsService;
    private TokenGenerator<?> tokenGenerator;
    private MiniAppSessionService miniAppSessionService;
    private Converter<HttpServletRequest, WechatMiniAppAuthenticationToken> requestResolver;

    public WechatMiniAppLoginFilterConfigurer(LoginFilterSecurityConfigurer<H> securityConfigurer) {
        super(securityConfigurer, new WechatMiniAppAuthenticationFilter(), LoginAntPathPatterns.WECHAT_MINIAPP.pattern());
    }

    public WechatMiniAppLoginFilterConfigurer<H> miniAppUserDetailsService(MiniAppUserDetailsService miniAppUserDetailsService) {
        this.miniAppUserDetailsService = miniAppUserDetailsService;
        return this;
    }

    public WechatMiniAppLoginFilterConfigurer<H> jwtTokenGenerator(TokenGenerator<?> tokenGenerator) {
        this.tokenGenerator = tokenGenerator;
        return this;
    }

    public WechatMiniAppLoginFilterConfigurer<H> miniAppSessionService(MiniAppSessionService miniAppSessionService) {
        this.miniAppSessionService = miniAppSessionService;
        return this;
    }

    public WechatMiniAppLoginFilterConfigurer<H> requestResolver(Converter<HttpServletRequest, WechatMiniAppAuthenticationToken> requestResolver) {
        this.requestResolver = requestResolver;
        return this;
    }

    @Override
    public void configure(H http) throws Exception {
        super.configure(http);
        if (requestResolver != null) {
            getAuthenticationFilter().setConverter(requestResolver);
        }
        configureSessionFilter(http);
    }

    private void configureSessionFilter(H http) {
        MiniAppSessionService sessionService = this.miniAppSessionService != null ? miniAppSessionService :
                getBeanOrNull(http, MiniAppSessionService.class);
        Assert.notNull(sessionService, "MiniAppSessionService must not be null");
        WechatMiniAppSessionAuthenticationFilter sessionAuthenticationFilter = new WechatMiniAppSessionAuthenticationFilter(sessionService);
        http.addFilterBefore(sessionAuthenticationFilter, HeaderWriterFilter.class);
    }

    @Override
    protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
        return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    }

    @Override
    protected AuthenticationProvider authenticationProvider(H http) {
        MiniAppUserDetailsService miniAppUserDetailsService = this.miniAppUserDetailsService != null ? this.miniAppUserDetailsService : getBeanOrNull(http, MiniAppUserDetailsService.class);
        Assert.notNull(miniAppUserDetailsService, "miniAppUserDetailsService is required");
        return new WechatMiniAppAuthenticationProvider(miniAppUserDetailsService);
    }

    @Override
    protected AuthenticationSuccessHandler defaultSuccessHandler(H http) {
        if (this.tokenGenerator == null) {
            tokenGenerator = getBeanOrNull(http, TokenGenerator.class);
        }
        Assert.notNull(tokenGenerator, "tokenGenerator is required");
        UserDetailsService userDetailsService = getBeanOrNull(http, UserDetailsService.class);
        Assert.notNull(userDetailsService, "userDetailsService is required");
        return new LoginAuthenticationSuccessHandler(tokenGenerator,userDetailsService);
    }
}
